package engine;

import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * Managing bigrams in documents
 * 
 * @author Vika
 * @author ak2765
 */
public final class BiGramFrequencies {

	private final Map<String,List<BiGram>> biGramsIndexedByLeftWords = new HashMap<String,List<BiGram>>();
	
	private final Map<BiGram,Integer> frequencies = new HashMap<BiGram,Integer>();

	private final List<BiGram> sortedBiGrams = new LinkedList<BiGram>(frequencies.keySet());
	
	public void addTitleWords(List<String> titleWords) {
		checkNull(titleWords, "titleWords");
		checkEmpty(titleWords, "titleWords");
		
		collectBiGrams(titleWords);
	}

	/**
	 * @param titleWords
	 */
	private void collectBiGrams(List<String> titleWords) {
		if (titleWords.size() == 1) {
			return; //no bigrams
		}
		
		for(int i=0;i<titleWords.size()-1;i++) {
			String left = titleWords.get(i);
			String right = titleWords.get(i+1);
			
			BiGram biGram = new BiGram(left, right);

			if (this.frequencies.containsKey(biGram)) {
				int count = this.frequencies.get(biGram);
				this.frequencies.put(biGram, count+1);
				
			} else {
				this.frequencies.put(biGram, 1);

				sortedBiGrams.add(biGram);
				
				Collections.sort(sortedBiGrams, new Comparator<BiGram>() {

					public int compare(BiGram o1, BiGram o2) {
						return frequencies.get(o2).compareTo(frequencies.get(o1));
					}
					
				});
				
				List<BiGram> indexedBiGrams = this.biGramsIndexedByLeftWords.get(left);
				if (indexedBiGrams == null) {
					indexedBiGrams = new LinkedList<BiGram>();
					this.biGramsIndexedByLeftWords.put(left, indexedBiGrams);
				}
				
				indexedBiGrams.add(biGram);
			}
		}
	}

	/**
	 * @param descriptionWords
	 */
	public void addDescriptionWords(List<String> descriptionWords) {
		checkNull(descriptionWords, "descriptionWords");
		checkEmpty(descriptionWords, "descriptionWords");
		
		collectBiGrams(descriptionWords);
	}

	/**
	 * @param words
	 * @param paramName
	 */
	private void checkEmpty(List<String> words, String paramName) {
		if (words.isEmpty()) {
			throw new IllegalArgumentException(paramName + "parameter list is empty");
		}
	}

	/**
	 * @param words
	 * @param paramName
	 */
	private void checkNull(List<String> words, String paramName) {
		if (words.isEmpty()) {
			throw new IllegalArgumentException(paramName + "parameter list is null");
		}
	}
	
	/**
	 * @return
	 */
	public List<BiGram> getTheTenPercentMorePopularBiGrams() {
		int tenPercent = this.sortedBiGrams.size() / 100;
		
		return this.sortedBiGrams.subList(0, tenPercent);
	}
	
	/**
	 * @param numberOfBiGrams
	 * @return
	 */
	public List<BiGram> getMoreFrequentBiGrams(int numberOfBiGrams) {
		if (sortedBiGrams.size() <= numberOfBiGrams) {
			return new LinkedList<BiGram>(sortedBiGrams);
		}
		
		return sortedBiGrams.subList(0, numberOfBiGrams-1);
	}
	
	/**
	 * @param biGram
	 * @return
	 */
	public int getFrequencyForBiGram(BiGram biGram) {
		if (false == frequencies.containsKey(biGram)) {
			return -1;
		}
		return frequencies.get(biGram);
	}

	/**
	 * @param leftWord
	 * @return
	 */
	public List<BiGram> getBiGramForLeftWord(String leftWord) {
		return this.biGramsIndexedByLeftWords.get(leftWord);
	}

	/**
	 * @return
	 */
	public List<BiGram> getBiGramsSortedByPopularity() {
		return new LinkedList<BiGram>(sortedBiGrams);
	}

}
